package com.gmail.dmitryustimov.ms.java7.visitor.mod_reflective.example.example2;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * Author: Dmitry Ustimov
 * Date: 5/10/13
 * Time: 10:33 AM
 */
public abstract class Visitor {

    public void visit(Visitable v) throws NoSuchMethodException {
        Method m = findMethod(v);
        try {
            m.invoke(this, new Object[] { v });
        }
        catch ( IllegalAccessException e1 ) {
            e1.printStackTrace();
        /* code handling */ }
        catch ( InvocationTargetException e2 ) {
            e2.printStackTrace();
        /* code handling */
        }
    }

    private Method findMethod(Visitable v) throws NoSuchMethodException {
        String methodName = "visit";
        Class visitable = v.getClass();
        while ( isAncestorOf("com.gmail.dmitryustimov.ms.java7.visitor.mod_reflective.reflective_work.Visitable", visitable)) {
            Class visitor = getClass();
            while ( isAncestorOf("com.gmail.dmitryustimov.ms.java7.visitor.mod_reflective.reflective_work.Visitor", visitor)) {
                try {
                    Method m = visitor.getDeclaredMethod(methodName,
                            new Class[]{visitable});
                    return m;
                } catch ( NoSuchMethodException e ) {
                    visitor = visitor.getSuperclass();
                }
            }
            visitable = visitable.getSuperclass();
        }
        String errMsg = "put error message here";
        throw new NoSuchMethodException(errMsg);
    }
    private boolean isAncestorOf(String ancestorName, Class descendant) {
        try {
            return Class.forName(ancestorName).isAssignableFrom(descendant);
        }
        catch ( ClassNotFoundException e ) { /* code handling */ }
        return false;
    }
}
